use std::borrow::Borrow;
use std::fmt;
use std::ops::Deref;
use std::str::Chars;

#[allow(dead_code)]
#[derive(Debug, Clone)]
pub enum Token {
    T_LP
    T_RP
    T_QUOTE
    T_NIL
    T_STRING(Box<str>)
    T_SYMBOL(Box<str>)
    T_INT(i64)
    T_FLOAT(f64)
}

#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct Tokenizor {
    s :Chars
    backputc: char
}

/// First line is a short summary describing function.
///
/// The next lines present detailed documentation. Code blocks start with
/// triple backquotes and have implicit `fn main()` inside
/// and `extern crate <cratename>`. Assume we're testing `doccomments` crate:
///
/// ```
/// let mut result = Tokenizor::new("(");
/// assert_eq!(result, T_LP);
/// ```
impl Tokenizor {
    fn new(s: str) -> Tokenizor {
        return Tokenizor {
            s: s.chars(),
            backputc:0,
        };
    }
    fn skip(&mut self) -> Option<char> {
        loop{
            let c = self.s.next();
            match c{
                None => return c,
                Some(c1) => match c1{
                    ' '|'\f'|'\r'|'\t'|'\n' => {
                        continue
                    },
                    _=>return Some(c1),
                },
            }
        }
        return None;
    }

    fn next(&mut self) -> Option<char> {
        if self.backputc!=0 {
            let c = Some(self.backputc);
            self.backputc = 0;
            return c;
        }
        return self.skip();
    }

    fn backput(&mut self,c: char)  {
        self.backputc = c;
    }


    fn scanint(&mut self,c char)->Option<Token>{
        let mut n:i64=0;
        let mut cc = c;
        'outer: loop {
            match cc.to_digit(10) {
                None => return None,
                Some(x) => n = 10*n+x,
            }
            match self.s.next(){
                None => break outer,
                Some(y) =>  match{
                    y.is_digit(10) => {cc = y;},
                    _=>{self.backput(y);break outer;},
                },
            }
        }
        return Some(n);
    }

    fn scan(&mut self)->Option<Token>{
        let c = self.next();
        match c{
            None => return c,
            Some(c1) => match c1{
                '(' => return T_LP,
                ')' => return T_RP,
                c1.is_digit(10) => return self.scanint(c1),
            },
        }
        return None;
    }
}
